package com.snap.vseries.analyze;

import android.util.Log;

import com.snap.vseries.bean.AnalysisProtocol;
import com.snap.vseries.bean.ChannelBean;
import com.snap.vseries.manager.ConfigManager;

import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;

import java.util.Arrays;
import java.util.List;

public class BaselineMa {

    private static final String TAG = "BaselineMa";

    public static void doAnalyze(List<ChannelBean> channelBeans, AnalysisProtocol analysisProtocol, AlgoParams algoParams) {
        double maxSlope = algoParams.getMaxSlope();
        double base = ConfigManager.getInstance().getSettingInfo().getLightBase();
        for (int i = 0; i < channelBeans.size(); i++) {
            curveSub(channelBeans.get(i), algoParams.getDefBaselineStart(), base, base * maxSlope);
        }
    }

    private static void curveSub(ChannelBean bean, int defBaselineStart, double base, double step) {
        if (bean == null || bean.getOrigin() == null || bean.getOrigin().length < 10) return;

        Log.e(TAG, "curveSub:通道 " + (bean.getChannelIndex() + 1) + "  孔：" + (bean.getHoleIndex() + 1));
        float[] data = bean.getOrigin().clone();

        //针对探针 或者染料 浓度放的过于高的情况下
        float a = 0;
        for (int i = 5; i < 10; i++) {
            a += data[i];
        }
        a /= 5;
        if (a > base * 1.2) {
            a /= base;
            for (int i = 0; i < data.length; i++) {
                data[i] /= a;
            }
            Log.e(TAG, "curveSub: 曲线被二次归一化" + Arrays.toString(data));
        }

        int start = defBaselineStart;
        int stop = getAutoEndPoint(data, start - 1, step) + 1;
        if (stop <= start) {
            start = 1;
        }

        bean.setBlStart(start);
        bean.setBlStop(stop);
        Log.e(TAG, "curveSub: 基线起点终点" + start + "~" + stop);
    }

    public static int getAutoEndPoint(float[] data, int start, double step) {
        if (data.length >= 10 && data.length - start >= 3) {//start不能过大 比如40里的37还行 38就不行了
            int j;
            for (int i = start; ; i++) {
                j = start;//这句大部分情况下没用  但是如果符合下面的条件  那j就被清空成传入的3了
                if (i >= data.length) {
                    break;//跳出循环的条件  i>=40 基本是40的时候跳出
                }
                j = i + 3;//j 比 i 大3
                if (j > data.length - 1) {// j=40 >39跳出  换句话就是j>=data.length
                    j = start;
                    break;//
                }
                //总结i和j任一达到40 跳出 跳出时 j都被置为3了。

                if (lineFit(data, i, j)[1] > 0.34D) {//从start 开始 以3或者说4为长度 滑动查斜率大于0.34的
                    float f = data[j]; //j的Rn值   以i=5 , j=8 为例  这是f(8)
                    j = i + 2;//j前面那个
                    if (f - data[j] > step) { //Rn比前一个值大50  f8比f7大50
                        f = data[j];//f赋值为 f7
                        j = i + 1;
                        if ((f - data[j] > step) //f7比f6大50
                                && (data[j] - data[i] > step)) { //f6比f5大50
                            return i;//返回的是小的那个 就是5。
                        }
                    }
                }
            }
            //能运行到此 j被还原到了3
            //找不到连续3个增幅大于50的。
            while (j < data.length) {
                if (j + 3 > data.length - 1) {//j=37时 跳出 返回39
                    return data.length - 1;
                }
                start = j + 1;//start=4
                if (data[start] - data[j] > step * 3.6) {
                    return j;//找到增幅一下大于180的。  最大能返回的j值为36  要么返回39
                }
                j = start;//换句话就是j++
            }
            return data.length - 1; //真的找不到  那就返回39  貌似唯一情况start=37 length=40才运行这句话
        }
        return data.length - 1;//
    }

    private static double[] lineFit(float[] data, int start, int stop) {
        WeightedObservedPoints points = new WeightedObservedPoints();
        for (int x = start; x <= stop; x++) {
            points.add(x + 1, data[x]);
        }
        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(1);
        return fitter.fit(points.toList());
    }
}
